package td;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public class Prototype {

	static Map map;
	
	private static void init() throws IOException{
		map = new Map("Files/protomap.txt","Files/waves1.txt");
		ArrayList<Field> f = new ArrayList<Field>();
		map.fields.add(f);
	}
	
	public static void main(String[] args) throws IOException {
		
		/*Creates an empty prototype map*/
		init();
		
		for (int inputcount = 0; inputcount < args.length; inputcount++) {
			String op = generateOutputPath(args[inputcount]);
			FileReader reader = new FileReader(args[inputcount]);
			BufferedReader input = new BufferedReader(reader);
			FileWriter writer = new FileWriter(op);
			BufferedWriter output = new BufferedWriter(writer);
			String line;
			/*Clears the map, so previous fields won't affect next test.*/
			map.fields.get(0).clear();
			/*We create a special two-way hashmap for the ID-s*/
			twoWayHashMap IDs = new twoWayHashMap();
			/*We add the maps player, so we can get it later by it's ID*/
			IDs.add("player1", map.player);
			
			while ((line = input.readLine()) != null) {
				String[] cmdLine = line.split(" ");
				/*Applies fog to given tower, if it exists*/
				if(cmdLine[0].equals("applyFog")){
					if(IDs.get(cmdLine[1])!=null && (IDs.get(cmdLine[1]) instanceof Tower)){
						((Tower) IDs.get(cmdLine[1])).applyFog();
						output.write("Applied fog on "+cmdLine[1]);
					}else{
						output.write("Error when applying fog on "+cmdLine[1]);
					}
				}
				/*Creates an ArcherTower on given field with given id. Tower can only be placed if it is not a road, and it doesn't contain a tower already*/
				else if(cmdLine[0].equals("createArcherTower")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(!field.isRoad && !field.hasTower){
							ArcherTower at = new ArcherTower(field);
							IDs.add(cmdLine[1], at);
							map.player.selected=(ArcherTower) IDs.get(cmdLine[1]);
							map.player.placeTower((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an CatapultTower on given field with given id. Tower can only be placed if it is not a road, and it doesn't contain a tower already*/
				else if(cmdLine[0].equals("createCatapultTower")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(!field.isRoad && !field.hasTower){
							CatapultTower ct = new CatapultTower(field);
							IDs.add(cmdLine[1], ct);
							map.player.selected=(CatapultTower) IDs.get(cmdLine[1]);
							map.player.placeTower((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates a Dwarf on given field, if it's a road, with given id*/
				else if(cmdLine[0].equals("createDwarf")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad){
							Dwarf dwarf1 = new Dwarf(field, map);
							IDs.add(cmdLine[1], dwarf1);
							((Field) IDs.get(cmdLine[2])).addElement(((Dwarf) IDs.get(cmdLine[1])));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an Elf on given field, if it's a road, with given id*/
				else if(cmdLine[0].equals("createElf")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad){
							Elf elf1 = new Elf(field, map);
							IDs.add(cmdLine[1], elf1);
							((Field) IDs.get(cmdLine[2])).addElement(((Elf) IDs.get(cmdLine[1])));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an endpoint field with given ID if that ID is not used yet.*/
				else if(cmdLine[0].equals("createEndPoint")){
					if(IDs.get(cmdLine[1])==null){
						Field end = new Field();
						end.isEndPoint=true;
						end.isRoad=true;
						IDs.add(cmdLine[1], end);
						map.fields.get(0).add((Field) IDs.get(cmdLine[1]));
						output.write(cmdLine[1]+" created");
					}else{
						output.write(cmdLine[1]+" cannot be created");
					}
				}
				/*Creates an Ent on given field, if it's a road, with given id*/
				else if(cmdLine[0].equals("createEnt")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad){
							Ent ent1 = new Ent(field, map);
							IDs.add(cmdLine[1], ent1);
							((Field) IDs.get(cmdLine[2])).addElement(((Ent) IDs.get(cmdLine[1])));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates a field with given ID if that ID is not used yet.*/
				else if(cmdLine[0].equals("createField")){
					if(IDs.get(cmdLine[1])==null){
						Field field = new Field();
						IDs.add(cmdLine[1], field);
						map.fields.get(0).add((Field) IDs.get(cmdLine[1]));
						output.write(cmdLine[1]+" created");
					}else{
						output.write(cmdLine[1]+" cannot be created");
					}
				}
				/*Creates an FireTrap on given field with given id. Trap can only be placed if it is a road, and it doesn't contain a trap already*/
				else if(cmdLine[0].equals("createFireTrap")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad && !field.hasTrap){
							FireTrap ft = new FireTrap(field);
							IDs.add(cmdLine[1], ft);
							map.player.selected=(FireTrap) IDs.get(cmdLine[1]);
							map.player.placeTrap((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an Ghost on given field, if it's a road, with given id*/
				else if(cmdLine[0].equals("createGhost")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad){
							Ghost ghost1 = new Ghost(field, map);
							IDs.add(cmdLine[1], ghost1);
							((Field) IDs.get(cmdLine[2])).addElement(((Ghost) IDs.get(cmdLine[1])));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an Hobbit on given field, if it's a road, with given id*/
				else if(cmdLine[0].equals("createHobbit")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad){
							Hobbit hobbit1 = new Hobbit(field, map);
							IDs.add(cmdLine[1], hobbit1);
							((Field) IDs.get(cmdLine[2])).addElement(((Hobbit) IDs.get(cmdLine[1])));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an Human on given field, if it's a road, with given id*/
				else if(cmdLine[0].equals("createHuman")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad){
							Human human1 = new Human(field, map);
							IDs.add(cmdLine[1], human1);
							((Field) IDs.get(cmdLine[2])).addElement(((Human) IDs.get(cmdLine[1])));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an OneTower on given field with given id. Tower can only be placed if it is not a road, and it doesn't contain a tower already*/
				else if(cmdLine[0].equals("createOneTower")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(!field.isRoad && !field.hasTower){
							OneTower ot = new OneTower(field);
							IDs.add(cmdLine[1], ot);
							map.player.selected=(OneTower) IDs.get(cmdLine[1]);
							map.player.placeTower((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates a road field with given ID if that ID is not in use yet.*/
				else if(cmdLine[0].equals("createRoad")){
					if(IDs.get(cmdLine[1])==null){
						Field road = new Field();
						road.isRoad=true;
						IDs.add(cmdLine[1], road);
						map.fields.get(0).add((Field) IDs.get(cmdLine[1]));
						output.write(cmdLine[1]+" created");
					}else{
						output.write(cmdLine[1]+" cannot be created");
					}
				}
				/*Creates an TwoTower on given field with given id. Tower can only be placed if it is not a road, and it doesn't contain a tower already*/
				else if(cmdLine[0].equals("createTwoTower")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(!field.isRoad && !field.hasTower){
							TwoTower tt = new TwoTower(field);
							IDs.add(cmdLine[1], tt);
							map.player.selected=(TwoTower) IDs.get(cmdLine[1]);
							map.player.placeTower((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an VineTrap on given field with given id. Trap can only be placed if it is a road, and it doesn't contain a trap already*/
				else if(cmdLine[0].equals("createVineTrap")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad && !field.hasTrap){
							VineTrap vt = new VineTrap(field);
							IDs.add(cmdLine[1], vt);
							map.player.selected=(VineTrap) IDs.get(cmdLine[1]);
							map.player.placeTrap((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Creates an WindTrap on given field with given id. Trap can only be placed if it is a road, and it doesn't contain a trap already*/
				else if(cmdLine[0].equals("createWindTrap")){
					if(IDs.get(cmdLine[1])==null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[2]) instanceof Field)){
						Field field = (Field) IDs.get(cmdLine[2]);
						if(field.isRoad && !field.hasTrap){
							WindTrap wt = new WindTrap(field);
							IDs.add(cmdLine[1], wt);
							map.player.selected=(WindTrap) IDs.get(cmdLine[1]);
							map.player.placeTrap((Field) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" created on field "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot be created on field "+cmdLine[2]);
					}
				}
				/*Makes two fields neighbours, and if they are roads, also steppable*/
				else if(cmdLine[0].equals("connectField")){
					if(IDs.get(cmdLine[1])!=null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[1]) instanceof Field) && (IDs.get(cmdLine[2]) instanceof Field)){
						((Field) IDs.get(cmdLine[1])).neighbours.add(((Field) IDs.get(cmdLine[2])));
						((Field) IDs.get(cmdLine[2])).neighbours.add(((Field) IDs.get(cmdLine[1])));
						if(((Field) IDs.get(cmdLine[1])).isRoad && ((Field) IDs.get(cmdLine[2])).isRoad){
							((Field) IDs.get(cmdLine[1])).nextSteppable.add(((Field) IDs.get(cmdLine[2])));
						}
						output.write(cmdLine[1]+" and "+cmdLine[2]+" connected successfully");
					}else{
						output.write("Error: Cannot connect "+cmdLine[1]+" and "+cmdLine[2]);
					}
				}
				/*Sells Tower with given id.*/
				else if(cmdLine[0].equals("sellTower")){
					if(IDs.get(cmdLine[1])!=null && (IDs.get(cmdLine[1]) instanceof Tower)){
						map.player.sellTower((Tower) IDs.get(cmdLine[1]));
						IDs.remove(cmdLine[1], IDs.get(cmdLine[1]));
						output.write(cmdLine[1]+" sold");
					}else{
						output.write("Error: "+cmdLine[1]+" does not exist.");
					}
				}
				/*Shoots a critical bullet from a rainbow upgraded archertower to given target*/
				else if(cmdLine[0].equals("shootCritical")){
					if(IDs.get(cmdLine[1])!=null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[1]) instanceof ArcherTower) && (IDs.get(cmdLine[2]) instanceof Enemy)){
						if(((ArcherTower) IDs.get(cmdLine[1])).inrange.contains(((Enemy) IDs.get(cmdLine[2])).position)){
							((ArcherTower) IDs.get(cmdLine[1])).shootCritical((Enemy) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" shot a critical bullet at "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot shoot "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot shoot "+cmdLine[2]);
					}
				}
				/*Shoots a cutterbullet from a tower to given target*/
				else if(cmdLine[0].equals("shootCutter")){
					if(IDs.get(cmdLine[1])!=null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[1]) instanceof Tower) && (IDs.get(cmdLine[2]) instanceof Enemy)){
						if(((Tower) IDs.get(cmdLine[1])).inrange.contains(((Enemy) IDs.get(cmdLine[2])).position)){
							((Tower) IDs.get(cmdLine[1])).shootCutter((Enemy) IDs.get(cmdLine[2]));
							output.write(cmdLine[1]+" shot "+cmdLine[2]);
							ArrayList<Enemy> smalls = ((Enemy) IDs.get(cmdLine[2])).position.getEnemies();
							for(int i=0; i<smalls.size(); i++){
								if(!smalls.get(i).equals(((Enemy) IDs.get(cmdLine[2])))){
									IDs.add("small"+(i+1), smalls.get(i));
								}
							}
							IDs.remove(cmdLine[2], IDs.get(cmdLine[2]));
						}else{
							output.write(cmdLine[1]+" cannot shoot "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot shoot "+cmdLine[2]);
					}
				}
				/*Given tower shoots at given target*/
				else if(cmdLine[0].equals("shootTower")){
					if(IDs.get(cmdLine[1])!=null && IDs.get(cmdLine[2])!=null && (IDs.get(cmdLine[1]) instanceof Tower) && (IDs.get(cmdLine[2]) instanceof Enemy)){
						if(((Tower) IDs.get(cmdLine[1])).inrange.contains(((Enemy) IDs.get(cmdLine[2])).position)){
							((Tower) IDs.get(cmdLine[1])).shoot((Enemy) IDs.get(cmdLine[2]));					
							output.write(cmdLine[1]+" shot "+cmdLine[2]);
						}else{
							output.write(cmdLine[1]+" cannot shoot "+cmdLine[2]);
						}
					}else{
						output.write(cmdLine[1]+" cannot shoot "+cmdLine[2]);
					}
				}
				/*Shows current state of prototype map*/
				else if(cmdLine[0].equals("showmap")){
					showMap(output);
				}
				/*Shows the state of given item.*/
				else if(cmdLine[0].equals("state")){
					if(IDs.get(cmdLine[1])!=null){
						getState(cmdLine[1],output, IDs);
					}else{
						output.write(cmdLine[1]+"does not exist");
					}
				}
				/*Steps given enemy from first given field to second given field, if they are neighbouring roads.*/
				else if(cmdLine[0].equals("stepEnemy")){
					if(IDs.get(cmdLine[1])!=null && IDs.get(cmdLine[2])!=null && IDs.get(cmdLine[3])!=null && (IDs.get(cmdLine[1]) instanceof Enemy) && (IDs.get(cmdLine[2]) instanceof Field) && (IDs.get(cmdLine[3]) instanceof Field)){
						if(((Enemy) IDs.get(cmdLine[1])).position.equals((Field)IDs.get(cmdLine[2]))){
							if(((Field)IDs.get(cmdLine[2])).nextSteppable.contains((Field)IDs.get(cmdLine[3]))){
								((Enemy) IDs.get(cmdLine[1])).step();
								output.write(cmdLine[1]+" stepped from "+cmdLine[2]+" to "+cmdLine[3]);
							}else{
								output.write(cmdLine[1]+" cannot step from "+cmdLine[2]+" to "+cmdLine[3]);
							}
						}else{
							output.write(cmdLine[1]+" cannot step from "+cmdLine[2]+" to "+cmdLine[3]);
						}
					}else{
						output.write(cmdLine[1]+" cannot step from "+cmdLine[2]+" to "+cmdLine[3]);
					}
				}
				/*Upgrades a given tower with given stone to given stoneplace*/
				else if(cmdLine[0].equals("upgradeTower")){
					if(IDs.get(cmdLine[1])!=null && (IDs.get(cmdLine[1]) instanceof Tower)){
						MagicStones ms = null;
						if(cmdLine[3].equals("BLUE"))
							ms = MagicStones.Blue;
						if(cmdLine[3].equals("RED"))
							ms = MagicStones.Red;
						if(cmdLine[3].equals("YELLOW"))
							ms = MagicStones.Yellow;
						if(cmdLine[3].equals("RAINBOW"))
							ms = MagicStones.Rainbow;
						((Tower) IDs.get(cmdLine[1])).upgrade(ms, Integer.parseInt(cmdLine[2]));
						output.write(cmdLine[1]+" upgraded with "+cmdLine[3]);
					}else{
						output.write(cmdLine[1]+" cannot be upgraded with "+cmdLine[3]);
					}
				}
				/*Upgrades a given trap with given stone*/
				else if(cmdLine[0].equals("upgradeTrap")){
					if(IDs.get(cmdLine[1])!=null && (IDs.get(cmdLine[1]) instanceof Trap)){
						MagicStones ms = null;
						if(cmdLine[2].equals("BLUE"))
							ms = MagicStones.Blue;
						if(cmdLine[2].equals("RED"))
							ms = MagicStones.Red;
						if(cmdLine[2].equals("YELLOW"))
							ms = MagicStones.Yellow;
						if(cmdLine[2].equals("RAINBOW"))
							ms = MagicStones.Rainbow;
						((Trap) IDs.get(cmdLine[1])).upgrade(ms);
						output.write(cmdLine[1]+" upgraded with "+cmdLine[2]);
					}else{
						output.write(cmdLine[1]+" cannot be upgraded with "+cmdLine[2]);
					}
				}
				output.newLine();
			}
			input.close();
			output.close();
		}
	}
	
	/*Method to get the state of the element given by ID from the hashmap*/
	public static void getState(String id, BufferedWriter output, twoWayHashMap ids) throws IOException {
		String stateClass = ids.get(id).getClass().toString();
		/*Output when we ask a field's attributes. Example:
		 * State of Field road1:
		 * 		elements: (small1,small2)
		 * 		neighbours: (field1)
		 * 		nextSteppable: (road2)
		 * 		hasTrap: false
		 * 		hasTower: false
		 * 		isRoad: true
		 * 		isStartPoint: false
		 * 		isEndPoint: false
		 * */
		if(stateClass.equals(Field.class.toString())){
			Field field = (Field) ids.get(id);
			ArrayList<FieldElement> fe= field.getElements();
			output.write("State of Field "+id+":");
			output.newLine();
			output.write("\telements: (");
			for(int i=0; i<fe.size(); i++){
				output.write(ids.get(fe.get(i)));
				if(i<fe.size()-1)
					output.write(",");
			}
			output.write(")");
			output.newLine();
			output.write("\tneighbours: (");
			for(int i=0; i<field.neighbours.size(); i++){
				output.write(ids.get(field.neighbours.get(i)));
				if(i<field.neighbours.size()-1)
					output.write(",");
			}
			output.write(")");
			output.newLine();
			output.write("\tnextSteppable: (");
			for(int i=0; i<field.nextSteppable.size(); i++){
				output.write(ids.get(field.nextSteppable.get(i)));
				if(i<field.nextSteppable.size()-1)
					output.write(",");
			}
			output.write(")");
			output.newLine();
			output.write("\thasTrap: "+field.hasTrap);
			output.newLine();
			output.write("\thasTower: "+field.hasTower);
			output.newLine();
			output.write("\tisRoad: "+field.isRoad);
			output.newLine();
			output.write("\tisStartPoint: "+field.isStartPoint);
			output.newLine();
			output.write("\tisEndPoint: "+field.isEndPoint);
		}
		/*Output when we ask an enemy's attributes. Example:
		 * State of Enemy elf1:
		 * 		position: road1
		 * 		hp: 15
		 * 		speed: 1.0
		 * 		value: 2
		 * 		damage: 2
		 * 		slowduration: 0
		 * 		fireduration: 0
		 * */
		else if(ids.get(id) instanceof Enemy){
			Enemy enemy = (Enemy) ids.get(id);
			output.write("State of Enemy "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(enemy.position));
			output.newLine();
			output.write("\thp: "+enemy.hp);
			output.newLine();
			output.write("\tspeed: "+enemy.speed);
			output.newLine();
			output.write("\tvalue: "+enemy.value);
			output.newLine();
			output.write("\tdamage: "+enemy.damage);
			output.newLine();
			output.write("\tslowduration: "+enemy.slowduration);
			output.newLine();
			output.write("\tfireduration: "+enemy.fireduration);
		}
		/*Output when we ask a firetrap's attributes. Example:
		 * State of Trap firetrap1:
		 * 		position: road1
		 * 		cooldownTime: 60
		 * 		damage: 2.0
		 * 		dmgType: OneShot
		 * */
		else if(stateClass.equals(FireTrap.class.toString())){
			FireTrap ft = (FireTrap) ids.get(id);
			output.write("State of Trap "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(ft.position));
			output.newLine();
			output.write("\tcooldownTime: "+ft.cooldownTime);
			output.newLine();
			output.write("\tdamage: "+ft.damage);
			output.newLine();
			output.write("\tdmgType: "+ft.dmgType);
		}
		/*Output when we ask a vinetrap's attributes. Example:
		 * State of Trap vinetrap1:
		 * 		position: road1
		 * 		cooldownTime: 20
		 * 		slowLevel: 1.0
		 * 		doesDmg: false
		 * */
		else if(stateClass.equals(VineTrap.class.toString())){
			VineTrap vt = (VineTrap) ids.get(id);
			output.write("State of Trap "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(vt.position));
			output.newLine();
			output.write("\tcooldownTime: "+vt.cooldownTime);
			output.newLine();
			output.write("\tslowLevel: "+vt.slowLevel);
			output.newLine();
			output.write("\tdoesDmg: "+vt.doesDmg);
		}
		/*Output when we ask a windtrap's attributes. Example:
		 * State of Trap windtrap1:
		 * 		position: road1
		 * 		cooldownTime: 40
		 * 		status: None
		 * 		pushback: 1
		 * */
		else if(stateClass.equals(WindTrap.class.toString())){
			WindTrap wt = (WindTrap) ids.get(id);
			output.write("State of Trap "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(wt.position));
			output.newLine();
			output.write("\tcooldownTime: "+wt.cooldownTime);
			output.newLine();
			output.write("\tstatus: "+wt.status);
			output.newLine();
			output.write("\tpushback: "+wt.pushback);
		}
		/*Output when we ask a archertower's attributes. Example:
		 * State of Tower archertower1:
		 * 		position: field1
		 * 		range: 3
		 * 		sliceChance: 10
		 * 		stones: (null,Blue)
		 * 		bullet: class td.SingleBullet(2,None)
		 * 		speed: 0.5
		 * 		cost: 40
		 * */
		else if(stateClass.equals(ArcherTower.class.toString())){
			ArcherTower at = (ArcherTower) ids.get(id);
			output.write("State of Tower "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(at.position));
			output.newLine();
			output.write("\trange: "+at.range);
			output.newLine();
			output.write("\tsliceChance: "+at.sliceChance);
			output.newLine();
			output.write("\tstones: "+"("+at.stones[0]+","+at.stones[1]+")");
			output.newLine();
			output.write("\tbullet: "+at.bullet.getClass().toString()+"("+at.bullet.damage+","+at.bullet.status+")");
			output.newLine();
			output.write("\tspeed: "+at.speed);
			output.newLine();
			output.write("\tcost: "+at.cost);
		}
		/*Output when we ask a catapulttower's attributes. Example:
		 * State of Tower catapulttower1:
		 * 		position: field1
		 * 		range: 2
		 * 		sliceChance: 10
		 * 		stones: (null,Red)
		 * 		bullet: class td.AoEBullet(4,None)
		 * 		speed: 2.0
		 * 		cost: 50
		 * */
		else if(stateClass.equals(CatapultTower.class.toString())){
			CatapultTower ct = (CatapultTower) ids.get(id);
			output.write("State of Tower "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(ct.position));
			output.newLine();
			output.write("\trange: "+ct.range);
			output.newLine();
			output.write("\tsliceChance: "+ct.sliceChance);
			output.newLine();
			output.write("\tstones: "+"("+ct.stones[0]+","+ct.stones[1]+")");
			output.newLine();
			output.write("\tbullet: "+ct.bullet.getClass().toString()+"("+ct.bullet.damage+","+ct.bullet.status+")");
			output.newLine();
			output.write("\tspeed: "+ct.speed);
			output.newLine();
			output.write("\tcost: "+ct.cost);
		}
		/*Output when we ask a onetower's attributes. Example:
		 * State of Tower onetower1:
		 * 		position: field1
		 * 		range: 2
		 * 		sliceChance: 10
		 * 		stones: (null,Red)
		 * 		bullet: class td.SingleBullet(4,None)
		 * 		speed: 1.0
		 * 		cost: 30
		 * */
		else if(stateClass.equals(OneTower.class.toString())){
			OneTower ot = (OneTower) ids.get(id);
			output.write("State of Tower "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(ot.position));
			output.newLine();
			output.write("\trange: "+ot.range);
			output.newLine();
			output.write("\tsliceChance: "+ot.sliceChance);
			output.newLine();
			output.write("\tstones: "+"("+ot.stones[0]+","+ot.stones[1]+")");
			output.newLine();
			output.write("\tbullet: "+ot.bullet.getClass().toString()+"("+ot.bullet.damage+","+ot.bullet.status+")");
			output.newLine();
			output.write("\tspeed: "+ot.speed);
			output.newLine();
			output.write("\tcost: "+ot.cost);
		}
		/*Output when we ask a twotower's attributes. Example:
		 * State of Tower twotower1:
		 * 		position: field1
		 * 		range: 3
		 * 		sliceChance: 10
		 * 		stones: (null,Yellow)
		 * 		bullet: class td.SingleBullet(5,None)
		 * 		speed: 1.0
		 * 		cost: 70
		 * 		dmgType: None
		 * */
		else if(stateClass.equals(TwoTower.class.toString())){
			TwoTower tt = (TwoTower) ids.get(id);
			output.write("State of Tower "+id+":");
			output.newLine();
			output.write("\tposition: "+ids.get(tt.position));
			output.newLine();
			output.write("\trange: "+tt.range);
			output.newLine();
			output.write("\tsliceChance: "+tt.sliceChance);
			output.newLine();
			output.write("\tstones: "+"("+tt.stones[0]+","+tt.stones[1]+")");
			output.newLine();
			output.write("\tbullet: "+tt.bullet.getClass().toString()+"("+tt.bullet.damage+","+tt.bullet.status+")");
			output.newLine();
			output.write("\tspeed: "+tt.speed);
			output.newLine();
			output.write("\tcost: "+tt.cost);
			output.newLine();
			output.write("\tdmgType: "+tt.dmgType);
		}
		/*Output when we ask the player's attributes. Example:
		 * State of Player player1:
		 *		hp: 20
		 *		mana: 150
		 * */
		else if(stateClass.equals(Player.class.toString())){
			output.write("State of Player player1:");
			output.newLine();
			output.write("\thp: "+map.player.getHp());
			output.newLine();
			output.write("\tmana: "+map.player.getMana());
		}
	}
	
	/* Shows us the current state of the map. Example:
	 * - - - - - - - - - - -
	 * - R R R R R R R R R -
	 * - R - - - R - - - R -
	 * - R - - - R - - - R -
	 * - R R R R R - - - R -
	 * S R - - - - - - - R M
	 * - R - - - R R R R R -
	 * - R - - - R - - - R -
	 * - R - - - R - - - R -
	 * - R R R R R R R R R -
	 * - - - - - - - - - - -
	 * */
	public static void showMap(BufferedWriter output) throws IOException{
		output.newLine();
		for(int i=0; i<map.fields.size(); i++){
			for(int j=0; j<map.fields.get(i).size(); j++){
				if(map.fields.get(i).get(j).isStartPoint){
					output.write("S");
					output.write(" ");
				}
				else if(map.fields.get(i).get(j).isEndPoint){
					output.write("E");
					output.write(" ");
				}
				else if(map.fields.get(i).get(j).isRoad){
					output.write("R");
					if(map.fields.get(i).get(j).hasTrap){
						Trap trap = map.fields.get(i).get(j).getTrap();
						if(trap instanceof VineTrap)
							output.write(",V");
						else if(trap instanceof WindTrap)
							output.write(",W");
						else if(trap instanceof FireTrap)
							output.write(",F");
					}
					output.write(" ");
				}
				else {
					output.write("-");
					output.write(" ");
				}
			}
			output.newLine();
		}
	}
	
	/*Generates the outputfile's path, with the input scriptfile's name+"Output".
	 * For example: test1.txt -> test1Output.txt */
	public static String generateOutputPath(String input) {
		return input.substring(0, input.lastIndexOf(".")) + "Output.txt";
	}
	
	/*Twoway hashmap to store elements and their ids.*/
	private static class twoWayHashMap{
		private HashMap<String, Object> fw = new HashMap<String, Object>();
		private HashMap<Object, String> bw = new HashMap<Object, String>();
		
		public void add(String key, Object value){
			fw.put(key, value);
			bw.put(value, key);
		}
		
		public Object get(String key){
			return fw.get(key);
		}
		
		public String get(Object value){
			return bw.get(value);
		}
		
		public void remove(String key, Object value){
			fw.remove(key);
			bw.remove(value);
		}
	}
}
